/*
 * Copyright (c) United Binary LLC.  All rights reserved.
 * 
 * This code is licensed under the MIT License
 * 
 * SEE: http://harnessit.codeplex.com/license
 * 
 */
using System;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.Win32;

namespace UnitedBinary.Core.Windows.Forms.Persistence
{
	/// <include file='Persistence.xml' path='/Docs/RecentFileManager/Class/*'/>
	public class RecentFileManager
	{
		private MenuItem rootItem;
		private RecentFile[] files = new RecentFile [0];
		private string subKeyPath = string.Empty;

		/// <include file='Persistence.xml' path='/Docs/RecentFileManager/FileClickEventHandler/*'/>
		public delegate void FileClickEventHandler(string filename);

		/// <include file='Persistence.xml' path='/Docs/RecentFileManager/FileClick/*'/>
		public event FileClickEventHandler FileClick;

		/// <include file='Persistence.xml' path='/Docs/RecentFileManager/ctor/*'/>
		public RecentFileManager(MenuItem rootItem, string subKeyPath)
		{
			this.rootItem = rootItem;
			Clear();

			char[] trimChars = {' ', '\\'};
			this.subKeyPath = "Software\\" + subKeyPath.Trim(trimChars) + "\\RecentFiles";

			Debug.WriteLine("RecentFileManager msg: Creating object with HKEY_CURRENT_USER\\" + this.subKeyPath + " as registry value.");

			LoadRecentFilesFromRegistry();
		}

		private void LoadRecentFilesFromRegistry()
		{
			RegistryKey key = Registry.CurrentUser.CreateSubKey(subKeyPath);

			ArrayList tmpFiles = new ArrayList();
			string baseName = "RecentFile";
			for (int i=0; i < 12; i++)
			{
				try
				{
					string keyName = baseName + (i+1);
					string file = (string)key.GetValue(keyName, "");
					if (file.Length > 0)
					{
						RecentFile rf = new RecentFile(file);
						if (rf.Exists)
						{
							tmpFiles.Add(rf);
						}
					}
				}
				catch(Exception e)
				{
					Debug.WriteLine("RecentFileManager msg: Error reading key " + baseName + (i+1) + ". Details: " + e.Message);
				}
			}

			files = new RecentFile [tmpFiles.Count];
			for (int i=0; i<tmpFiles.Count; i++)
			{
				files[i] = (RecentFile)tmpFiles[i];
			}

			RebuildRecentFiles();
		}

		/// <include file='Persistence.xml' path='/Docs/RecentFileManager/Clear/*'/>
		public void Clear()
		{
			files = new RecentFile [0];
			rootItem.MenuItems.Clear();

			MenuItem empty = new MenuItem("(Empty)");
			empty.Enabled = false;
			rootItem.MenuItems.Add(empty);
		}

		/// <include file='Persistence.xml' path='/Docs/RecentFileManager/Save/*'/>
		public void Save()
		{
			SaveRecentFilesToRegistry();
		}

		private void SaveRecentFilesToRegistry()
		{
			RegistryKey key = Registry.CurrentUser.CreateSubKey(subKeyPath);

			string baseName = "RecentFile";
			// Clear out the old values (in case of reordering and what not).
			for (int i=0; i < 12; i++)
			{
				try
				{
					string keyName = baseName + (i+1);
					key.SetValue(keyName, "");
				}
				catch(Exception e)
				{
					Debug.WriteLine("RecentFileManager msg: Error writing key " + baseName + (i+1) + ". Details: " + e.Message);
				}
			}

			// Add the new values to the registry.
			for (int i=0; i < files.Length; i++)
			{
				try
				{
					string keyName = baseName + (i+1);
					key.SetValue(keyName, files[i].FileName);
				}
				catch(Exception e)
				{
					Debug.WriteLine("RecentFileManager msg: Error writing key " + baseName + (i+1) + ". Details: " + e.Message);
				}
			}
		}

		private void menuItem_Click(object sender, System.EventArgs e)
		{
			MenuItem item = (MenuItem)sender;
			Debug.WriteLine("RecentFileManager msg: Selected recent file " + ((RecentFile)files[item.Index]).FileName);
			if (FileClick != null)
			{
				Debug.WriteLine("RecentFileManager msg: Firing FileClick event.");
				FileClick(((RecentFile)files[item.Index]).FileName);
			}
			else
			{
				Debug.WriteLine("RecentFileManager WARNING: No listeners for the FileClick event registered. Menu will have no effect.");
			}
		}

		/// <include file='Persistence.xml' path='/Docs/RecentFileManager/Add/*'/>
		public void Add(string file)
		{
			if (!FileAlreadyExists(file))
			{
				AddNewFile(file);
			}
			else
			{
				UpdateExistingFile(file);
			}

			RebuildRecentFiles();
		}

		private void AddNewFile(string file)
		{
			if (file[0] != '\\' && file[1] != ':')
			{
				Debug.WriteLine("RecentFileManager: Relative paths cannot be saved, skipping AddFile.");
				return;
			}

			int len = files.Length;
			RecentFile[] tmpFiles = new RecentFile [len+1];
			for (int i=files.Length; i > 0; i--)
			{
				tmpFiles[i] = files[i-1];
			}
			tmpFiles[0] = new RecentFile(file);

			files = new RecentFile [System.Math.Min(12, len+1)];
			for (int i=0; i < files.Length; i++)
			{
				files[i] = tmpFiles[i];
			}
		}

		private void UpdateExistingFile(string file)
		{
			int index = 0;
			for (int i=0; i < files.Length; i++)
			{
				if (files[i].FileName == file)
				{
					index = i;
					break;
				}
			}

			RecentFile tmpFile = files[index];
			for (int i=index; i > 0; i--)
			{
				files[i] = files[i-1];
			}
			files[0] = tmpFile;
		}

		private bool FileAlreadyExists(string file)
		{
			foreach (RecentFile f in files)
			{
				if (f.FileName.ToLower() == file.ToLower())
					return true;
			}
			return false;
		}

		private void RebuildRecentFiles()
		{
			if (files.Length == 0)
			{
				Clear();
				return;
			}

			try
			{
				rootItem.MenuItems.Clear();

				for (int i=0; i < files.Length; i++)
				{
					rootItem.MenuItems.Add(new MenuItem(files[i].FileName, new System.EventHandler(this.menuItem_Click)));
				}
			}
			catch(Exception e)
			{
				Debug.WriteLine("Error rebuilding recent file list.  Details: " + e.Message);
			}
		}
	}
}
